package f.h.dragon.util;

import java.io.Serializable;
import java.util.Comparator;

/**
 * Object with boost
 * 
 * @author Wenlong Meng(wenlong.meng@gmail.com)
 * @version 1.0 at 2011/11/17
 * @since 1.0
 */
public class WeightObject implements Comparable<WeightObject>, Serializable {
	
	//local variables
	/**
	 * uid
	 */
	private static final long serialVersionUID = 278759633378302593L;
	/**
	 * storage
	 */
	private IStorage storage = Storage.malloc();
	/**
	 * sort desc： 降序
	 */
	public static Comparator<WeightObject> DESC = new OrderDesc();
	/**
	 * sort asc： 升序
	 */
	public static Comparator<WeightObject> ASC = new OrderAsc();
	
	//setter and getter
	/**
	 * @return the obj
	 */
	@SuppressWarnings("unchecked")
	public <T> T getObj() {
		return (T)this.storage.get("_obj");
	}
	/**
	 * @param obj the obj to set
	 */
	public <T> void setObj(T obj) {
		this.storage.put("_obj", obj);
	}
	
	/**
	 * @return the weights
	 */
	public float[] getWeights() {
		return this.storage.get("_weights");
	}
	/**
	 * @param weights the weights to set
	 */
	public void setWeights(float[] weights) {
		this.storage.put("_weights", weights);
	}
	
	//Logic
	/**
     * Compares this object with the specified object for order.  Returns a
     * negative integer, zero, or a positive integer as this object is less
     * than, equal to, or greater than the specified object.
     *
     * <p>The implementor must ensure <tt>sgn(x.compareTo(y)) ==
     * -sgn(y.compareTo(x))</tt> for all <tt>x</tt> and <tt>y</tt>.  (This
     * implies that <tt>x.compareTo(y)</tt> must throw an exception iff
     * <tt>y.compareTo(x)</tt> throws an exception.)
     *
     * <p>The implementor must also ensure that the relation is transitive:
     * <tt>(x.compareTo(y)&gt;0 &amp;&amp; y.compareTo(z)&gt;0)</tt> implies
     * <tt>x.compareTo(z)&gt;0</tt>.
     *
     * <p>Finally, the implementor must ensure that <tt>x.compareTo(y)==0</tt>
     * implies that <tt>sgn(x.compareTo(z)) == sgn(y.compareTo(z))</tt>, for
     * all <tt>z</tt>.
     *
     * <p>It is strongly recommended, but <i>not</i> strictly required that
     * <tt>(x.compareTo(y)==0) == (x.equals(y))</tt>.  Generally speaking, any
     * class that implements the <tt>Comparable</tt> interface and violates
     * this condition should clearly indicate this fact.  The recommended
     * language is "Note: this class has a natural ordering that is
     * inconsistent with equals."
     *
     * <p>In the foregoing description, the notation
     * <tt>sgn(</tt><i>expression</i><tt>)</tt> designates the mathematical
     * <i>signum</i> function, which is defined to return one of <tt>-1</tt>,
     * <tt>0</tt>, or <tt>1</tt> according to whether the value of
     * <i>expression</i> is negative, zero or positive.
     *
     * @param   o the object to be compared.
     * @return  a negative integer, zero, or a positive integer as this object
     *		is less than, equal to, or greater than the specified object.
     *
     * @throws ClassCastException if the specified object's type prevents it
     *         from being compared to this object.
     */
	@Override
	public int compareTo(WeightObject o) {
		//the weights of o is empty: return 1
		if(o == null || o.getWeights() == null){
			return -1;
		}
		//the weights of this object is empty: return -1
		if(this.getWeights() == null){
			return 1;
		}
		
		//comparable
		for(int i = 0, count = Math.min(o.getWeights().length, this.getWeights().length); i < count; i++){
			if(this.getWeights()[i] != o.getWeights()[i]){
				return this.getWeights()[i] > o.getWeights()[i] ? -1 : 1;
			}
		}
		return 0;
	}
	
	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return "WeightObject [storage=" + storage + "]";
	}
	
	/**
	 * OrderDesc: 依据WeightObject的weights值比较：
	 * 	1、大于则返回-1
	 * 	2、等于则返回0
	 * 	3、小于则返回1
	 *
	 * @author Wenlong Meng(wenlong.meng@gmail.com)
	 * @version 1.0 at 2012/02/13
	 * @since 1.0
	 */
	public static class OrderDesc implements Comparator<WeightObject> {
		
		//Logic
		/**
		 * Compares its two arguments for order.  Returns a negative integer,
		 * zero, or a positive integer as the first argument is greater than, equal
		 * to, or less than the second.<p>
		 * 
		 * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
		 * 
		 * @param o1
		 * @param o2
		 * @return a negative integer, zero, or a positive integer as the
		 * 	       first argument is greater than, equal to, or less than the
		 *	       second.
		 */
		@Override
		public int compare(WeightObject o1, WeightObject o2) {
			if(o1 == null){
				return o2 == null ? 0 : 1;
			}
			
			return -o1.compareTo(o2);
		}
	}
	
	/**
	 * OrderAsc: 依据WeightObject的weights值比较：
	 * 	1、大于则返回1
	 * 	2、等于则返回0
	 * 	3、小于则返回-1
	 *
	 * @author Wenlong Meng(wenlong.meng@gmail.com)
	 * @version 1.0 at 2012/02/13
	 * @since 1.0
	 */
	public static class OrderAsc implements Comparator<WeightObject> {
		
		//Logic
		/**
		 * Compares its two arguments for order.  Returns a negative integer,
		 * zero, or a positive integer as the first argument is less than, equal
		 * to, or greater than the second.<p>
		 * 
		 * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
		 * 
		 * @param o1
		 * @param o2
		 * @return a negative integer, zero, or a positive integer as the
		 * 	       first argument is less than, equal to, or greater than the
		 *	       second.
		 */
		@Override
		public int compare(WeightObject o1, WeightObject o2) {
			if(o1 == null){
				return o2 == null ? 0 : -1;
			}
			
			return o1.compareTo(o2);
		}
	}
	
	/**
	 * Order: 排序标识
	 * 	ASC: 升序序， 默认方式
	 * 	DESC：降序
	 *
	 * @author Wenlong Meng(wenlong.meng@gmail.com)
	 * @version 1.0 at 2012/02/13
	 * @since 1.0
	 */
	public static enum Order {
		ASC,
		DESC
	}
	
	/**
	 * testing...
	 * 
	 * @param args
	 */
	public static void main(String[] args){
		WeightObject bo1 = new WeightObject();
		bo1.setObj(11);
		float[] boost1 = {2, 2, 33};
		bo1.setWeights(boost1);
		WeightObject bo2 = new WeightObject();
		bo2.setObj(22);
		float[] boost2 = {2, 2, 22};
		bo2.setWeights(boost2);
		System.out.println(bo1.compareTo(bo2));

	}

}
